home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible (2nd Edition) / OpenGL SuperBible e2.iso / tools / GLUT-3.7 / PROGS / EXAMPLES / GLPUZZLE.C < prev    next >
Encoding:
C/C++ Source or Header  |  1998-08-12  |  28.7 KB  |  1,440 lines

  1.  
  2. /* glpuzzle - written by Kevin Smith (kpsmith@engr.sgi.com) */
  3.  
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <sys/types.h>
  8. #include <time.h>
  9. #include <math.h>
  10. #include <GL/glut.h>
  11. #include "trackball.h"
  12.  
  13. #define WIDTH 4
  14. #define HEIGHT 5
  15. #define PIECES 10
  16. #define OFFSETX -2
  17. #define OFFSETY -2.5
  18. #define OFFSETZ -0.5
  19.  
  20. typedef unsigned char Config[HEIGHT][WIDTH];
  21.  
  22. struct puzzle {
  23.   struct puzzle *backptr;
  24.   struct puzzle *solnptr;
  25.   Config pieces;
  26.   struct puzzle *next;
  27.   unsigned hashvalue;
  28. };
  29.  
  30. #define HASHSIZE 10691
  31.  
  32. struct puzzlelist {
  33.   struct puzzle *puzzle;
  34.   struct puzzlelist *next;
  35. };
  36.  
  37. static char convert[PIECES + 1] =
  38. {0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 4};
  39.  
  40. static unsigned char colors[PIECES + 1][3] =
  41. {
  42.   {0, 0, 0},
  43.   {255, 255, 127},
  44.   {255, 255, 127},
  45.   {255, 255, 127},
  46.   {255, 255, 127},
  47.   {255, 127, 255},
  48.   {255, 127, 255},
  49.   {255, 127, 255},
  50.   {255, 127, 255},
  51.   {255, 127, 127},
  52.   {255, 255, 255},
  53. };
  54.  
  55. void changeState(void);
  56.  
  57. static struct puzzle *hashtable[HASHSIZE];
  58. static struct puzzle *startPuzzle;
  59. static struct puzzlelist *puzzles;
  60. static struct puzzlelist *lastentry;
  61.  
  62. int curX, curY, visible;
  63.  
  64. #define MOVE_SPEED 0.2
  65. static unsigned char movingPiece;
  66. static float move_x, move_y;
  67. static float curquat[4];
  68. static int doubleBuffer = 1;
  69. static int depth = 1;
  70.  
  71. static char xsize[PIECES + 1] =
  72. {0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2};
  73. static char ysize[PIECES + 1] =
  74. {0, 1, 1, 1, 1, 2, 2, 2, 2, 1, 2};
  75. static float zsize[PIECES + 1] =
  76. {0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.6};
  77.  
  78. static Config startConfig =
  79. {
  80.   {8, 10, 10, 7},
  81.   {8, 10, 10, 7},
  82.   {6, 9, 9, 5},
  83.   {6, 4, 3, 5},
  84.   {2, 0, 0, 1}
  85. };
  86.  
  87. static Config thePuzzle =
  88. {
  89.   {8, 10, 10, 7},
  90.   {8, 10, 10, 7},
  91.   {6, 9, 9, 5},
  92.   {6, 4, 3, 5},
  93.   {2, 0, 0, 1}
  94. };
  95.  
  96. static int xadds[4] =
  97. {-1, 0, 1, 0};
  98. static int yadds[4] =
  99. {0, -1, 0, 1};
  100.  
  101. static int W = 400, H = 300;
  102. static GLint viewport[4];
  103.  
  104. #define srandom srand
  105. #define random() (rand() >> 2)
  106.  
  107. unsigned
  108. hash(Config config)
  109. {
  110.   int i, j, value;
  111.  
  112.   value = 0;
  113.   for (i = 0; i < HEIGHT; i++) {
  114.     for (j = 0; j < WIDTH; j++) {
  115.       value = value + convert[config[i][j]];
  116.       value *= 6;
  117.     }
  118.   }
  119.   return (value);
  120. }
  121.  
  122. int
  123. solution(Config config)
  124. {
  125.   if (config[4][1] == 10 && config[4][2] == 10)
  126.     return (1);
  127.   return (0);
  128. }
  129.  
  130. float boxcoords[][3] =
  131. {
  132.   {0.2, 0.2, 0.9},
  133.   {0.8, 0.2, 0.9},
  134.   {0.8, 0.8, 0.9},
  135.   {0.2, 0.8, 0.9},
  136.   {0.2, 0.1, 0.8},
  137.   {0.8, 0.1, 0.8},
  138.   {0.9, 0.2, 0.8},
  139.   {0.9, 0.8, 0.8},
  140.   {0.8, 0.9, 0.8},
  141.   {0.2, 0.9, 0.8},
  142.   {0.1, 0.8, 0.8},
  143.   {0.1, 0.2, 0.8},
  144.   {0.2, 0.1, 0.2},
  145.   {0.8, 0.1, 0.2},
  146.   {0.9, 0.2, 0.2},
  147.   {0.9, 0.8, 0.2},
  148.   {0.8, 0.9, 0.2},
  149.   {0.2, 0.9, 0.2},
  150.   {0.1, 0.8, 0.2},
  151.   {0.1, 0.2, 0.2},
  152.   {0.2, 0.2, 0.1},
  153.   {0.8, 0.2, 0.1},
  154.   {0.8, 0.8, 0.1},
  155.   {0.2, 0.8, 0.1},
  156. };
  157.  
  158. float boxnormals[][3] =
  159. {
  160.   {0, 0, 1},            /* 0 */
  161.   {0, 1, 0},
  162.   {1, 0, 0},
  163.   {0, 0, -1},
  164.   {0, -1, 0},
  165.   {-1, 0, 0},
  166.   {0.7071, 0.7071, 0.0000},  /* 6 */
  167.   {0.7071, -0.7071, 0.0000},
  168.   {-0.7071, 0.7071, 0.0000},
  169.   {-0.7071, -0.7071, 0.0000},
  170.   {0.7071, 0.0000, 0.7071},  /* 10 */
  171.   {0.7071, 0.0000, -0.7071},
  172.   {-0.7071, 0.0000, 0.7071},
  173.   {-0.7071, 0.0000, -0.7071},
  174.   {0.0000, 0.7071, 0.7071},  /* 14 */
  175.   {0.0000, 0.7071, -0.7071},
  176.   {0.0000, -0.7071, 0.7071},
  177.   {0.0000, -0.7071, -0.7071},
  178.   {0.5774, 0.5774, 0.5774},  /* 18 */
  179.   {0.5774, 0.5774, -0.5774},
  180.   {0.5774, -0.5774, 0.5774},
  181.   {0.5774, -0.5774, -0.5774},
  182.   {-0.5774, 0.5774, 0.5774},
  183.   {-0.5774, 0.5774, -0.5774},
  184.   {-0.5774, -0.5774, 0.5774},
  185.   {-0.5774, -0.5774, -0.5774},
  186. };
  187.  
  188. int boxfaces[][4] =
  189. {
  190.   {0, 1, 2, 3},         /* 0 */
  191.   {9, 8, 16, 17},
  192.   {6, 14, 15, 7},
  193.   {20, 23, 22, 21},
  194.   {12, 13, 5, 4},
  195.   {19, 11, 10, 18},
  196.   {7, 15, 16, 8},       /* 6 */
  197.   {13, 14, 6, 5},
  198.   {18, 10, 9, 17},
  199.   {19, 12, 4, 11},
  200.   {1, 6, 7, 2},         /* 10 */
  201.   {14, 21, 22, 15},
  202.   {11, 0, 3, 10},
  203.   {20, 19, 18, 23},
  204.   {3, 2, 8, 9},         /* 14 */
  205.   {17, 16, 22, 23},
  206.   {4, 5, 1, 0},
  207.   {20, 21, 13, 12},
  208.   {2, 7, 8, -1},        /* 18 */
  209.   {16, 15, 22, -1},
  210.   {5, 6, 1, -1},
  211.   {13, 21, 14, -1},
  212.   {10, 3, 9, -1},
  213.   {18, 17, 23, -1},
  214.   {11, 4, 0, -1},
  215.   {20, 12, 19, -1},
  216. };
  217.  
  218. #define NBOXFACES (sizeof(boxfaces)/sizeof(boxfaces[0]))
  219.  
  220. /* Draw a box.  Bevel as desired. */
  221. void
  222. drawBox(int piece, float xoff, float yoff)
  223. {
  224.   int xlen, ylen;
  225.   int i, k;
  226.   float x, y, z;
  227.   float zlen;
  228.   float *v;
  229.  
  230.   xlen = xsize[piece];
  231.   ylen = ysize[piece];
  232.   zlen = zsize[piece];
  233.  
  234.   glColor3ubv(colors[piece]);
  235.   glBegin(GL_QUADS);
  236.   for (i = 0; i < 18; i++) {
  237.     glNormal3fv(boxnormals[i]);
  238.     for (k = 0; k < 4; k++) {
  239.       if (boxfaces[i][k] == -1)
  240.         continue;
  241.       v = boxcoords[boxfaces[i][k]];
  242.       x = v[0] + OFFSETX;
  243.       if (v[0] > 0.5)
  244.         x += xlen - 1;
  245.       y = v[1] + OFFSETY;
  246.       if (v[1] > 0.5)
  247.         y += ylen - 1;
  248.       z = v[2] + OFFSETZ;
  249.       if (v[2] > 0.5)
  250.         z += zlen - 1;
  251.       glVertex3f(xoff + x, yoff + y, z);
  252.     }
  253.   }
  254.   glEnd();
  255.   glBegin(GL_TRIANGLES);
  256.   for (i = 18; i < NBOXFACES; i++) {
  257.     glNormal3fv(boxnormals[i]);
  258.     for (k = 0; k < 3; k++) {
  259.       if (boxfaces[i][k] == -1)
  260.         continue;
  261.       v = boxcoords[boxfaces[i][k]];
  262.       x = v[0] + OFFSETX;
  263.       if (v[0] > 0.5)
  264.         x += xlen - 1;
  265.       y = v[1] + OFFSETY;
  266.       if (v[1] > 0.5)
  267.         y += ylen - 1;
  268.       z = v[2] + OFFSETZ;
  269.       if (v[2] > 0.5)
  270.         z += zlen - 1;
  271.       glVertex3f(xoff + x, yoff + y, z);
  272.     }
  273.   }
  274.   glEnd();
  275. }
  276.  
  277. float containercoords[][3] =
  278. {
  279.   {-0.1, -0.1, 1.0},
  280.   {-0.1, -0.1, -0.1},
  281.   {4.1, -0.1, -0.1},
  282.   {4.1, -0.1, 1.0},
  283.   {1.0, -0.1, 0.6},     /* 4 */
  284.   {3.0, -0.1, 0.6},
  285.   {1.0, -0.1, 0.0},
  286.   {3.0, -0.1, 0.0},
  287.   {1.0, 0.0, 0.0},      /* 8 */
  288.   {3.0, 0.0, 0.0},
  289.   {3.0, 0.0, 0.6},
  290.   {1.0, 0.0, 0.6},
  291.   {0.0, 0.0, 1.0},      /* 12 */
  292.   {4.0, 0.0, 1.0},
  293.   {4.0, 0.0, 0.0},
  294.   {0.0, 0.0, 0.0},
  295.   {0.0, 5.0, 0.0},      /* 16 */
  296.   {0.0, 5.0, 1.0},
  297.   {4.0, 5.0, 1.0},
  298.   {4.0, 5.0, 0.0},
  299.   {-0.1, 5.1, -0.1},    /* 20 */
  300.   {4.1, 5.1, -0.1},
  301.   {4.1, 5.1, 1.0},
  302.   {-0.1, 5.1, 1.0},
  303. };
  304.  
  305. float containernormals[][3] =
  306. {
  307.   {0, -1, 0},
  308.   {0, -1, 0},
  309.   {0, -1, 0},
  310.   {0, -1, 0},
  311.   {0, -1, 0},
  312.   {0, 1, 0},
  313.   {0, 1, 0},
  314.   {0, 1, 0},
  315.   {1, 0, 0},
  316.   {1, 0, 0},
  317.   {1, 0, 0},
  318.   {-1, 0, 0},
  319.   {-1, 0, 0},
  320.   {-1, 0, 0},
  321.   {0, 1, 0},
  322.   {0, 0, -1},
  323.   {0, 0, -1},
  324.   {0, 0, 1},
  325.   {0, 0, 1},
  326.   {0, 0, 1},
  327.   {0, 0, 1},
  328.   {0, 0, 1},
  329.   {0, 0, 1},
  330.   {0, 0, 1},
  331. };
  332.  
  333. int containerfaces[][4] =
  334. {
  335.   {1, 6, 4, 0},
  336.   {0, 4, 5, 3},
  337.   {1, 2, 7, 6},
  338.   {7, 2, 3, 5},
  339.   {16, 19, 18, 17},
  340.  
  341.   {23, 22, 21, 20},
  342.   {12, 11, 8, 15},
  343.   {10, 13, 14, 9},
  344.  
  345.   {15, 16, 17, 12},
  346.   {2, 21, 22, 3},
  347.   {6, 8, 11, 4},
  348.  
  349.   {1, 0, 23, 20},
  350.   {14, 13, 18, 19},
  351.   {9, 7, 5, 10},
  352.  
  353.   {12, 13, 10, 11},
  354.  
  355.   {1, 20, 21, 2},
  356.   {4, 11, 10, 5},
  357.  
  358.   {15, 8, 19, 16},
  359.   {19, 8, 9, 14},
  360.   {8, 6, 7, 9},
  361.   {0, 3, 13, 12},
  362.   {13, 3, 22, 18},
  363.   {18, 22, 23, 17},
  364.   {17, 23, 0, 12},
  365. };
  366.  
  367. #define NCONTFACES (sizeof(containerfaces)/sizeof(containerfaces[0]))
  368.  
  369. /* Draw the container */
  370. void
  371. drawContainer(void)
  372. {
  373.   int i, k;
  374.   float *v;
  375.  
  376.   /* Y is reversed here because the model has it reversed */
  377.  
  378.   /* Arbitrary bright wood-like color */
  379.   glColor3ub(209, 103, 23);
  380.   glBegin(GL_QUADS);
  381.   for (i = 0; i < NCONTFACES; i++) {
  382.     v = containernormals[i];
  383.     glNormal3f(v[0], -v[1], v[2]);
  384.     for (k = 3; k >= 0; k--) {
  385.       v = containercoords[containerfaces[i][k]];
  386.       glVertex3f(v[0] + OFFSETX, -(v[1] + OFFSETY), v[2] + OFFSETZ);
  387.     }
  388.   }
  389.   glEnd();
  390. }
  391.  
  392. void
  393. drawAll(void)
  394. {
  395.   int i, j;
  396.   int piece;
  397.   char done[PIECES + 1];
  398.   float m[4][4];
  399.  
  400.   build_rotmatrix(m, curquat);
  401.   glMatrixMode(GL_MODELVIEW);
  402.   glLoadIdentity();
  403.   glTranslatef(0, 0, -10);
  404.   glMultMatrixf(&(m[0][0]));
  405.   glRotatef(180, 0, 0, 1);
  406.  
  407.   if (depth) {
  408.     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  409.   } else {
  410.     glClear(GL_COLOR_BUFFER_BIT);
  411.   }
  412.   for (i = 1; i <= PIECES; i++) {
  413.     done[i] = 0;
  414.   }
  415.   glLoadName(0);
  416.   drawContainer();
  417.   for (i = 0; i < HEIGHT; i++) {
  418.     for (j = 0; j < WIDTH; j++) {
  419.       piece = thePuzzle[i][j];
  420.       if (piece == 0)
  421.         continue;
  422.       if (done[piece])
  423.         continue;
  424.       done[piece] = 1;
  425.       glLoadName(piece);
  426.       if (piece == movingPiece) {
  427.         drawBox(piece, move_x, move_y);
  428.       } else {
  429.         drawBox(piece, j, i);
  430.       }
  431.     }
  432.   }
  433. }
  434.  
  435. void
  436. redraw(void)
  437. {
  438.   glMatrixMode(GL_PROJECTION);
  439.   glLoadIdentity();
  440.   gluPerspective(45, 1.0, 0.1, 100.0);
  441.  
  442.   drawAll();
  443.  
  444.   if (doubleBuffer)
  445.     glutSwapBuffers();
  446.   else
  447.     glFinish();
  448. }
  449.  
  450. void
  451. solidifyChain(struct puzzle *puzzle)
  452. {
  453.   int i;
  454.   char buf[256];
  455.  
  456.   i = 0;
  457.   while (puzzle->backptr) {
  458.     i++;
  459.     puzzle->backptr->solnptr = puzzle;
  460.     puzzle = puzzle->backptr;
  461.   }
  462.   sprintf(buf, "%d moves to complete!", i);
  463.   glutSetWindowTitle(buf);
  464. }
  465.  
  466. int
  467. addConfig(Config config, struct puzzle *back)
  468. {
  469.   unsigned hashvalue;
  470.   struct puzzle *newpiece;
  471.   struct puzzlelist *newlistentry;
  472.  
  473.   hashvalue = hash(config);
  474.  
  475.   newpiece = hashtable[hashvalue % HASHSIZE];
  476.   while (newpiece != NULL) {
  477.     if (newpiece->hashvalue == hashvalue) {
  478.       int i, j;
  479.  
  480.       for (i = 0; i < WIDTH; i++) {
  481.         for (j = 0; j < HEIGHT; j++) {
  482.           if (convert[config[j][i]] !=
  483.             convert[newpiece->pieces[j][i]])
  484.             goto nomatch;
  485.         }
  486.       }
  487.       return 0;
  488.     }
  489.   nomatch:
  490.     newpiece = newpiece->next;
  491.   }
  492.  
  493.   newpiece = (struct puzzle *) malloc(sizeof(struct puzzle));
  494.   newpiece->next = hashtable[hashvalue % HASHSIZE];
  495.   newpiece->hashvalue = hashvalue;
  496.   memcpy(newpiece->pieces, config, HEIGHT * WIDTH);
  497.   newpiece->backptr = back;
  498.   newpiece->solnptr = NULL;
  499.   hashtable[hashvalue % HASHSIZE] = newpiece;
  500.  
  501.   newlistentry = (struct puzzlelist *) malloc(sizeof(struct puzzlelist));
  502.   newlistentry->puzzle = newpiece;
  503.   newlistentry->next = NULL;
  504.  
  505.   if (lastentry) {
  506.     lastentry->next = newlistentry;
  507.   } else {
  508.     puzzles = newlistentry;
  509.   }
  510.   lastentry = newlistentry;
  511.  
  512.   if (back == NULL) {
  513.     startPuzzle = newpiece;
  514.   }
  515.   if (solution(config)) {
  516.     solidifyChain(newpiece);
  517.     return 1;
  518.   }
  519.   return 0;
  520. }
  521.  
  522. /* Checks if a space can move */
  523. int
  524. canmove0(Config pieces, int x, int y, int dir, Config newpieces)
  525. {
  526.   char piece;
  527.   int xadd, yadd;
  528.   int l, m;
  529.  
  530.   xadd = xadds[dir];
  531.   yadd = yadds[dir];
  532.  
  533.   if (x + xadd < 0 || x + xadd >= WIDTH ||
  534.     y + yadd < 0 || y + yadd >= HEIGHT)
  535.     return 0;
  536.   piece = pieces[y + yadd][x + xadd];
  537.   if (piece == 0)
  538.     return 0;
  539.   memcpy(newpieces, pieces, HEIGHT * WIDTH);
  540.   for (l = 0; l < WIDTH; l++) {
  541.     for (m = 0; m < HEIGHT; m++) {
  542.       if (newpieces[m][l] == piece)
  543.         newpieces[m][l] = 0;
  544.     }
  545.   }
  546.   xadd = -xadd;
  547.   yadd = -yadd;
  548.   for (l = 0; l < WIDTH; l++) {
  549.     for (m = 0; m < HEIGHT; m++) {
  550.       if (pieces[m][l] == piece) {
  551.         int newx, newy;
  552.  
  553.         newx = l + xadd;
  554.         newy = m + yadd;
  555.         if (newx < 0 || newx >= WIDTH ||
  556.           newy < 0 || newy >= HEIGHT)
  557.           return 0;
  558.         if (newpieces[newy][newx] != 0)
  559.           return 0;
  560.         newpieces[newy][newx] = piece;
  561.       }
  562.     }
  563.   }
  564.   return 1;
  565. }
  566.  
  567. /* Checks if a piece can move */
  568. int
  569. canmove(Config pieces, int x, int y, int dir, Config newpieces)
  570. {
  571.   int xadd, yadd;
  572.  
  573.   xadd = xadds[dir];
  574.   yadd = yadds[dir];
  575.  
  576.   if (x + xadd < 0 || x + xadd >= WIDTH ||
  577.     y + yadd < 0 || y + yadd >= HEIGHT)
  578.     return 0;
  579.   if (pieces[y + yadd][x + xadd] == pieces[y][x]) {
  580.     return canmove(pieces, x + xadd, y + yadd, dir, newpieces);
  581.   }
  582.   if (pieces[y + yadd][x + xadd] != 0)
  583.     return 0;
  584.   return canmove0(pieces, x + xadd, y + yadd, (dir + 2) % 4, newpieces);
  585. }
  586.  
  587. int
  588. generateNewConfigs(struct puzzle *puzzle)
  589. {
  590.   int i, j, k;
  591.   Config pieces;
  592.   Config newpieces;
  593.  
  594.   memcpy(pieces, puzzle->pieces, HEIGHT * WIDTH);
  595.   for (i = 0; i < WIDTH; i++) {
  596.     for (j = 0; j < HEIGHT; j++) {
  597.       if (pieces[j][i] == 0) {
  598.         for (k = 0; k < 4; k++) {
  599.           if (canmove0(pieces, i, j, k, newpieces)) {
  600.             if (addConfig(newpieces, puzzle))
  601.               return 1;
  602.           }
  603.         }
  604.       }
  605.     }
  606.   }
  607.   return 0;
  608. }
  609.  
  610. void
  611. freeSolutions(void)
  612. {
  613.   struct puzzlelist *nextpuz;
  614.   struct puzzle *puzzle, *next;
  615.   int i;
  616.  
  617.   while (puzzles) {
  618.     nextpuz = puzzles->next;
  619.     free((char *) puzzles);
  620.     puzzles = nextpuz;
  621.   }
  622.   lastentry = NULL;
  623.   for (i = 0; i < HASHSIZE; i++) {
  624.     puzzle = hashtable[i];
  625.     hashtable[i] = NULL;
  626.     while (puzzle) {
  627.       next = puzzle->next;
  628.       free((char *) puzzle);
  629.       puzzle = next;
  630.     }
  631.   }
  632.   startPuzzle = NULL;
  633. }
  634.  
  635. int
  636. continueSolving(void)
  637. {
  638.   struct puzzle *nextpuz;
  639.   int i, j;
  640.   int movedPiece;
  641.   int movedir;
  642.   int fromx, fromy;
  643.   int tox, toy;
  644.  
  645.   if (startPuzzle == NULL)
  646.     return 0;
  647.   if (startPuzzle->solnptr == NULL) {
  648.     freeSolutions();
  649.     return 0;
  650.   }
  651.   nextpuz = startPuzzle->solnptr;
  652.   movedPiece = 0;
  653.   movedir = 0;
  654.   for (i = 0; i < HEIGHT; i++) {
  655.     for (j = 0; j < WIDTH; j++) {
  656.       if (startPuzzle->pieces[i][j] != nextpuz->pieces[i][j]) {
  657.         if (startPuzzle->pieces[i][j]) {
  658.           movedPiece = startPuzzle->pieces[i][j];
  659.           fromx = j;
  660.           fromy = i;
  661.           if (i < HEIGHT - 1 && nextpuz->pieces[i + 1][j] == movedPiece) {
  662.             movedir = 3;
  663.           } else {
  664.             movedir = 2;
  665.           }
  666.           goto found_piece;
  667.         } else {
  668.           movedPiece = nextpuz->pieces[i][j];
  669.           if (i < HEIGHT - 1 &&
  670.             startPuzzle->pieces[i + 1][j] == movedPiece) {
  671.             fromx = j;
  672.             fromy = i + 1;
  673.             movedir = 1;
  674.           } else {
  675.             fromx = j + 1;
  676.             fromy = i;
  677.             movedir = 0;
  678.           }
  679.           goto found_piece;
  680.         }
  681.       }
  682.     }
  683.   }
  684.   glutSetWindowTitle("What!  No change?");
  685.   freeSolutions();
  686.   return 0;
  687.  
  688. found_piece:
  689.   if (!movingPiece) {
  690.     movingPiece = movedPiece;
  691.     move_x = fromx;
  692.     move_y = fromy;
  693.   }
  694.   move_x += xadds[movedir] * MOVE_SPEED;
  695.   move_y += yadds[movedir] * MOVE_SPEED;
  696.  
  697.   tox = fromx + xadds[movedir];
  698.   toy = fromy + yadds[movedir];
  699.  
  700.   if (move_x > tox - MOVE_SPEED / 2 && move_x < tox + MOVE_SPEED / 2 &&
  701.     move_y > toy - MOVE_SPEED / 2 && move_y < toy + MOVE_SPEED / 2) {
  702.     startPuzzle = nextpuz;
  703.     movingPiece = 0;
  704.   }
  705.   memcpy(thePuzzle, startPuzzle->pieces, HEIGHT * WIDTH);
  706.   changeState();
  707.   return 1;
  708. }
  709.  
  710. int
  711. solvePuzzle(void)
  712. {
  713.   struct puzzlelist *nextpuz;
  714.   char buf[256];
  715.   int i;
  716.  
  717.   if (solution(thePuzzle)) {
  718.     glutSetWindowTitle("Puzzle already solved!");
  719.     return 0;
  720.   }
  721.   addConfig(thePuzzle, NULL);
  722.   i = 0;
  723.  
  724.   while (puzzles) {
  725.     i++;
  726.     if (generateNewConfigs(puzzles->puzzle))
  727.       break;
  728.     nextpuz = puzzles->next;
  729.     free((char *) puzzles);
  730.     puzzles = nextpuz;
  731.   }
  732.   if (puzzles == NULL) {
  733.     freeSolutions();
  734.     sprintf(buf, "I can't solve it! (%d positions examined)", i);
  735.     glutSetWindowTitle(buf);
  736.     return 1;
  737.   }
  738.   return 1;
  739. }
  740.  
  741. int
  742. selectPiece(int mousex, int mousey)
  743. {
  744.   long hits;
  745.   GLuint selectBuf[1024];
  746.   GLuint closest;
  747.   GLuint dist;
  748.  
  749.   glSelectBuffer(1024, selectBuf);
  750.   (void) glRenderMode(GL_SELECT);
  751.   glInitNames();
  752.  
  753.   /* Because LoadName() won't work with no names on the stack */
  754.   glPushName(-1);
  755.  
  756.   glMatrixMode(GL_PROJECTION);
  757.   glLoadIdentity();
  758.   gluPickMatrix(mousex, H - mousey, 4, 4, viewport);
  759.   gluPerspective(45, 1.0, 0.1, 100.0);
  760.  
  761.   drawAll();
  762.  
  763.   hits = glRenderMode(GL_RENDER);
  764.   if (hits <= 0) {
  765.     return 0;
  766.   }
  767.   closest = 0;
  768.   dist = 4294967295U;
  769.   while (hits) {
  770.     if (selectBuf[(hits - 1) * 4 + 1] < dist) {
  771.       dist = selectBuf[(hits - 1) * 4 + 1];
  772.       closest = selectBuf[(hits - 1) * 4 + 3];
  773.     }
  774.     hits--;
  775.   }
  776.   return closest;
  777. }
  778.  
  779. void
  780. nukePiece(int piece)
  781. {
  782.   int i, j;
  783.  
  784.   for (i = 0; i < HEIGHT; i++) {
  785.     for (j = 0; j < WIDTH; j++) {
  786.       if (thePuzzle[i][j] == piece) {
  787.         thePuzzle[i][j] = 0;
  788.       }
  789.     }
  790.   }
  791. }
  792.  
  793. void
  794. multMatrices(const GLfloat a[16], const GLfloat b[16], GLfloat r[16])
  795. {
  796.   int i, j;
  797.  
  798.   for (i = 0; i < 4; i++) {
  799.     for (j = 0; j < 4; j++) {
  800.       r[i * 4 + j] =
  801.         a[i * 4 + 0] * b[0 * 4 + j] +
  802.         a[i * 4 + 1] * b[1 * 4 + j] +
  803.         a[i * 4 + 2] * b[2 * 4 + j] +
  804.         a[i * 4 + 3] * b[3 * 4 + j];
  805.     }
  806.   }
  807. }
  808.  
  809. void
  810. makeIdentity(GLfloat m[16])
  811. {
  812.   m[0 + 4 * 0] = 1;
  813.   m[0 + 4 * 1] = 0;
  814.   m[0 + 4 * 2] = 0;
  815.   m[0 + 4 * 3] = 0;
  816.   m[1 + 4 * 0] = 0;
  817.   m[1 + 4 * 1] = 1;
  818.   m[1 + 4 * 2] = 0;
  819.   m[1 + 4 * 3] = 0;
  820.   m[2 + 4 * 0] = 0;
  821.   m[2 + 4 * 1] = 0;
  822.   m[2 + 4 * 2] = 1;
  823.   m[2 + 4 * 3] = 0;
  824.   m[3 + 4 * 0] = 0;
  825.   m[3 + 4 * 1] = 0;
  826.   m[3 + 4 * 2] = 0;
  827.   m[3 + 4 * 3] = 1;
  828. }
  829.  
  830. /*
  831.    ** inverse = invert(src)
  832.  */
  833. int
  834. invertMatrix(const GLfloat src[16], GLfloat inverse[16])
  835. {
  836.   int i, j, k, swap;
  837.   double t;
  838.   GLfloat temp[4][4];
  839.  
  840.   for (i = 0; i < 4; i++) {
  841.     for (j = 0; j < 4; j++) {
  842.       temp[i][j] = src[i * 4 + j];
  843.     }
  844.   }
  845.   makeIdentity(inverse);
  846.  
  847.   for (i = 0; i < 4; i++) {
  848.     /* 
  849.        ** Look for largest element in column */
  850.     swap = i;
  851.     for (j = i + 1; j < 4; j++) {
  852.       if (fabs(temp[j][i]) > fabs(temp[i][i])) {
  853.         swap = j;
  854.       }
  855.     }
  856.  
  857.     if (swap != i) {
  858.       /* 
  859.          ** Swap rows. */
  860.       for (k = 0; k < 4; k++) {
  861.         t = temp[i][k];
  862.         temp[i][k] = temp[swap][k];
  863.         temp[swap][k] = t;
  864.  
  865.         t = inverse[i * 4 + k];
  866.         inverse[i * 4 + k] = inverse[swap * 4 + k];
  867.         inverse[swap * 4 + k] = t;
  868.       }
  869.     }
  870.     if (temp[i][i] == 0) {
  871.       /* 
  872.          ** No non-zero pivot.  The matrix is singular, which
  873.          shouldn't ** happen.  This means the user gave us a
  874.          bad matrix. */
  875.       return 0;
  876.     }
  877.     t = temp[i][i];
  878.     for (k = 0; k < 4; k++) {
  879.       temp[i][k] /= t;
  880.       inverse[i * 4 + k] /= t;
  881.     }
  882.     for (j = 0; j < 4; j++) {
  883.       if (j != i) {
  884.         t = temp[j][i];
  885.         for (k = 0; k < 4; k++) {
  886.           temp[j][k] -= temp[i][k] * t;
  887.           inverse[j * 4 + k] -= inverse[i * 4 + k] * t;
  888.         }
  889.       }
  890.     }
  891.   }
  892.   return 1;
  893. }
  894.  
  895. /*
  896.    ** This is a screwball function.  What it does is the following:
  897.    ** Given screen x and y coordinates, compute the corresponding object space 
  898.    **   x and y coordinates given that the object space z is 0.9 + OFFSETZ.
  899.    ** Since the tops of (most) pieces are at z = 0.9 + OFFSETZ, we use that 
  900.    **   number.
  901.  */
  902. int
  903. computeCoords(int piece, int mousex, int mousey,
  904.   GLfloat * selx, GLfloat * sely)
  905. {
  906.   GLfloat modelMatrix[16];
  907.   GLfloat projMatrix[16];
  908.   GLfloat finalMatrix[16];
  909.   GLfloat in[4];
  910.   GLfloat a, b, c, d;
  911.   GLfloat top, bot;
  912.   GLfloat z;
  913.   GLfloat w;
  914.   GLfloat height;
  915.  
  916.   if (piece == 0)
  917.     return 0;
  918.   height = zsize[piece] - 0.1 + OFFSETZ;
  919.  
  920.   glGetFloatv(GL_PROJECTION_MATRIX, projMatrix);
  921.   glGetFloatv(GL_MODELVIEW_MATRIX, modelMatrix);
  922.   multMatrices(modelMatrix, projMatrix, finalMatrix);
  923.   if (!invertMatrix(finalMatrix, finalMatrix))
  924.     return 0;
  925.  
  926.   in[0] = (2.0 * (mousex - viewport[0]) / viewport[2]) - 1;
  927.   in[1] = (2.0 * ((H - mousey) - viewport[1]) / viewport[3]) - 1;
  928.  
  929.   a = in[0] * finalMatrix[0 * 4 + 2] +
  930.     in[1] * finalMatrix[1 * 4 + 2] +
  931.     finalMatrix[3 * 4 + 2];
  932.   b = finalMatrix[2 * 4 + 2];
  933.   c = in[0] * finalMatrix[0 * 4 + 3] +
  934.     in[1] * finalMatrix[1 * 4 + 3] +
  935.     finalMatrix[3 * 4 + 3];
  936.   d = finalMatrix[2 * 4 + 3];
  937.  
  938.   /* 
  939.      ** Ok, now we need to solve for z: **   (a + b z) / (c + d 
  940.  
  941.      z) = height. ** ("height" is the height in object space we 
  942.  
  943.      want to solve z for) ** ** ==>  a + b z = height c +
  944.      height d z **      bz - height d z = height c - a ** z =
  945.      (height c - a) / (b - height d) */
  946.   top = height * c - a;
  947.   bot = b - height * d;
  948.   if (bot == 0.0)
  949.     return 0;
  950.  
  951.   z = top / bot;
  952.  
  953.   /* 
  954.      ** Ok, no problem. ** Now we solve for x and y.  We know
  955.      that w = c + d z, so we compute it. */
  956.   w = c + d * z;
  957.  
  958.   /* 
  959.      ** Now for x and y: */
  960.   *selx = (in[0] * finalMatrix[0 * 4 + 0] +
  961.     in[1] * finalMatrix[1 * 4 + 0] +
  962.     z * finalMatrix[2 * 4 + 0] +
  963.     finalMatrix[3 * 4 + 0]) / w - OFFSETX;
  964.   *sely = (in[0] * finalMatrix[0 * 4 + 1] +
  965.     in[1] * finalMatrix[1 * 4 + 1] +
  966.     z * finalMatrix[2 * 4 + 1] +
  967.     finalMatrix[3 * 4 + 1]) / w - OFFSETY;
  968.   return 1;
  969. }
  970.  
  971. static int selected;
  972. static int selectx, selecty;
  973. static float selstartx, selstarty;
  974.  
  975. void
  976. grabPiece(int piece, float selx, float sely)
  977. {
  978.   int hit;
  979.  
  980.   selectx = selx;
  981.   selecty = sely;
  982.   if (selectx < 0 || selecty < 0 || selectx >= WIDTH || selecty >= HEIGHT) {
  983.     return;
  984.   }
  985.   hit = thePuzzle[selecty][selectx];
  986.   if (hit != piece)
  987.     return;
  988.   if (hit) {
  989.     movingPiece = hit;
  990.     while (selectx > 0 && thePuzzle[selecty][selectx - 1] == movingPiece) {
  991.       selectx--;
  992.     }
  993.     while (selecty > 0 && thePuzzle[selecty - 1][selectx] == movingPiece) {
  994.       selecty--;
  995.     }
  996.     move_x = selectx;
  997.     move_y = selecty;
  998.     selected = 1;
  999.     selstartx = selx;
  1000.     selstarty = sely;
  1001.   } else {
  1002.     selected = 0;
  1003.   }
  1004.   changeState();
  1005. }
  1006.  
  1007. void
  1008. moveSelection(float selx, float sely)
  1009. {
  1010.   float deltax, deltay;
  1011.   int dir;
  1012.   Config newpieces;
  1013.  
  1014.   if (!selected)
  1015.     return;
  1016.   deltax = selx - selstartx;
  1017.   deltay = sely - selstarty;
  1018.  
  1019.   if (fabs(deltax) > fabs(deltay)) {
  1020.     deltay = 0;
  1021.     if (deltax > 0) {
  1022.       if (deltax > 1)
  1023.         deltax = 1;
  1024.       dir = 2;
  1025.     } else {
  1026.       if (deltax < -1)
  1027.         deltax = -1;
  1028.       dir = 0;
  1029.     }
  1030.   } else {
  1031.     deltax = 0;
  1032.     if (deltay > 0) {
  1033.       if (deltay > 1)
  1034.         deltay = 1;
  1035.       dir = 3;
  1036.     } else {
  1037.       if (deltay < -1)
  1038.         deltay = -1;
  1039.       dir = 1;
  1040.     }
  1041.   }
  1042.   if (canmove(thePuzzle, selectx, selecty, dir, newpieces)) {
  1043.     move_x = deltax + selectx;
  1044.     move_y = deltay + selecty;
  1045.     if (deltax > 0.5) {
  1046.       memcpy(thePuzzle, newpieces, HEIGHT * WIDTH);
  1047.       selectx++;
  1048.       selstartx++;
  1049.     } else if (deltax < -0.5) {
  1050.       memcpy(thePuzzle, newpieces, HEIGHT * WIDTH);
  1051.       selectx--;
  1052.       selstartx--;
  1053.     } else if (deltay > 0.5) {
  1054.       memcpy(thePuzzle, newpieces, HEIGHT * WIDTH);
  1055.       selecty++;
  1056.       selstarty++;
  1057.     } else if (deltay < -0.5) {
  1058.       memcpy(thePuzzle, newpieces, HEIGHT * WIDTH);
  1059.       selecty--;
  1060.       selstarty--;
  1061.     }
  1062.   } else {
  1063.     if (deltay > 0 && thePuzzle[selecty][selectx] == 10 &&
  1064.       selectx == 1 && selecty == 3) {
  1065.       /* Allow visual movement of solution piece outside of the 
  1066.  
  1067.          box */
  1068.       move_x = selectx;
  1069.       move_y = sely - selstarty + selecty;
  1070.     } else {
  1071.       move_x = selectx;
  1072.       move_y = selecty;
  1073.     }
  1074.   }
  1075. }
  1076.  
  1077. void
  1078. dropSelection(void)
  1079. {
  1080.   if (!selected)
  1081.     return;
  1082.   movingPiece = 0;
  1083.   selected = 0;
  1084.   changeState();
  1085. }
  1086.  
  1087. static int left_mouse, middle_mouse;
  1088. static int mousex, mousey;
  1089. static int solving;
  1090. static int spinning;
  1091. static float lastquat[4];
  1092. static int sel_piece;
  1093.  
  1094. static void
  1095. Reshape(int width, int height)
  1096. {
  1097.  
  1098.   W = width;
  1099.   H = height;
  1100.   glViewport(0, 0, W, H);
  1101.   glGetIntegerv(GL_VIEWPORT, viewport);
  1102. }
  1103.  
  1104. void
  1105. toggleSolve(void)
  1106. {
  1107.     if (solving) {
  1108.       freeSolutions();
  1109.       solving = 0;
  1110.       glutChangeToMenuEntry(1, "Solving", 1);
  1111.       glutSetWindowTitle("glpuzzle");
  1112.       movingPiece = 0;
  1113.     } else {
  1114.       glutChangeToMenuEntry(1, "Stop solving", 1);
  1115.       glutSetWindowTitle("Solving...");
  1116.       if (solvePuzzle()) {
  1117.         solving = 1;
  1118.       }
  1119.     }
  1120.     changeState();
  1121.     glutPostRedisplay();
  1122. }
  1123.  
  1124. void reset(void)
  1125. {
  1126.     if (solving) {
  1127.       freeSolutions();
  1128.       solving = 0;
  1129.       glutChangeToMenuEntry(1, "Solving", 1);
  1130.       movingPiece = 0;
  1131.       changeState();
  1132.     }
  1133.     glutSetWindowTitle("glpuzzle");
  1134.     memcpy(thePuzzle, startConfig, HEIGHT * WIDTH);
  1135.     glutPostRedisplay();
  1136. }
  1137.  
  1138. void
  1139. keyboard(unsigned char c, int x, int y)
  1140. {
  1141.   int piece;
  1142.  
  1143.   switch (c) {
  1144.   case 27:
  1145.     exit(0);
  1146.     break;
  1147.   case 'D':
  1148.   case 'd':
  1149.     if (solving) {
  1150.       freeSolutions();
  1151.       solving = 0;
  1152.       glutChangeToMenuEntry(1, "Solving", 1);
  1153.       glutSetWindowTitle("glpuzzle");
  1154.       movingPiece = 0;
  1155.       changeState();
  1156.     }
  1157.     piece = selectPiece(x, y);
  1158.     if (piece) {
  1159.       nukePiece(piece);
  1160.     }
  1161.     glutPostRedisplay();
  1162.     break;
  1163.   case 'R':
  1164.   case 'r':
  1165.     reset();
  1166.     break;
  1167.   case 'S':
  1168.   case 's':
  1169.     toggleSolve();
  1170.     break;
  1171.   case 'b':
  1172.   case 'B':
  1173.     depth = 1 - depth;
  1174.     if (depth) {
  1175.       glEnable(GL_DEPTH_TEST);
  1176.     } else {
  1177.       glDisable(GL_DEPTH_TEST);
  1178.     }
  1179.     glutPostRedisplay();
  1180.     break;
  1181.   default:
  1182.     break;
  1183.   }
  1184. }
  1185.  
  1186. void
  1187. motion(int x, int y)
  1188. {
  1189.   float selx, sely;
  1190.  
  1191.   if (middle_mouse && !left_mouse) {
  1192.     if (mousex != x || mousey != y) {
  1193.       trackball(lastquat,
  1194.         (2.0*mousex - W) / W,
  1195.         (H - 2.0*mousey) / H,
  1196.         (2.0*x - W) / W,
  1197.         (H - 2.0*y) / H);
  1198.       spinning = 1;
  1199.     } else {
  1200.       spinning = 0;
  1201.     }
  1202.     changeState();
  1203.   } else {
  1204.     computeCoords(sel_piece, x, y, &selx, &sely);
  1205.     moveSelection(selx, sely);
  1206.   }
  1207.   mousex = x;
  1208.   mousey = y;
  1209.   glutPostRedisplay();
  1210. }
  1211.  
  1212. void
  1213. mouse(int b, int s, int x, int y)
  1214. {
  1215.   float selx, sely;
  1216.  
  1217.   mousex = x;
  1218.   mousey = y;
  1219.   curX = x;
  1220.   curY = y;
  1221.   if (s == GLUT_DOWN) {
  1222.     switch (b) {
  1223.     case GLUT_LEFT_BUTTON:
  1224.       if (solving) {
  1225.         freeSolutions();
  1226.         solving = 0;
  1227.       glutChangeToMenuEntry(1, "Solving", 1);
  1228.         glutSetWindowTitle("glpuzzle");
  1229.         movingPiece = 0;
  1230.       }
  1231.       left_mouse = GL_TRUE;
  1232.       sel_piece = selectPiece(mousex, mousey);
  1233.       if (computeCoords(sel_piece, mousex, mousey, &selx, &sely)) {
  1234.         grabPiece(sel_piece, selx, sely);
  1235.       }
  1236.       glutPostRedisplay();
  1237.       break;
  1238.     case GLUT_MIDDLE_BUTTON:
  1239.       middle_mouse = GL_TRUE;
  1240.       glutPostRedisplay();
  1241.       break;
  1242.     }
  1243.   } else {
  1244.     switch (b) {
  1245.     case GLUT_LEFT_BUTTON:
  1246.       left_mouse = GL_FALSE;
  1247.       dropSelection();
  1248.       glutPostRedisplay();
  1249.       break;
  1250.     case GLUT_MIDDLE_BUTTON:
  1251.       middle_mouse = GL_FALSE;
  1252.       glutPostRedisplay();
  1253.       break;
  1254.     }
  1255.   }
  1256.   motion(x, y);
  1257. }
  1258.  
  1259. void
  1260. animate(void)
  1261. {
  1262.   if (spinning) {
  1263.     add_quats(lastquat, curquat, curquat);
  1264.   }
  1265.   glutPostRedisplay();
  1266.   if (solving) {
  1267.     if (!continueSolving()) {
  1268.       solving = 0;
  1269.       glutChangeToMenuEntry(1, "Solving", 1);
  1270.       glutSetWindowTitle("glpuzzle");
  1271.     }
  1272.   }
  1273.   if (!solving && !spinning && !visible) {
  1274.     glutIdleFunc(NULL);
  1275.   }
  1276. }
  1277.  
  1278. void
  1279. changeState(void)
  1280. {
  1281.   if (visible) {
  1282.     if (!solving && !spinning) {
  1283.       glutIdleFunc(NULL);
  1284.     } else {
  1285.       glutIdleFunc(animate);
  1286.     }
  1287.   } else {
  1288.     glutIdleFunc(NULL);
  1289.   }
  1290. }
  1291.  
  1292. void
  1293. init(void)
  1294. {
  1295.   static float lmodel_ambient[] =
  1296.   {0.0, 0.0, 0.0, 0.0};
  1297.   static float lmodel_twoside[] =
  1298.   {GL_FALSE};
  1299.   static float lmodel_local[] =
  1300.   {GL_FALSE};
  1301.   static float light0_ambient[] =
  1302.   {0.1, 0.1, 0.1, 1.0};
  1303.   static float light0_diffuse[] =
  1304.   {1.0, 1.0, 1.0, 0.0};
  1305.   static float light0_position[] =
  1306.   {0.8660254, 0.5, 1, 0};
  1307.   static float light0_specular[] =
  1308.   {0.0, 0.0, 0.0, 0.0};
  1309.   static float bevel_mat_ambient[] =
  1310.   {0.0, 0.0, 0.0, 1.0};
  1311.   static float bevel_mat_shininess[] =
  1312.   {40.0};
  1313.   static float bevel_mat_specular[] =
  1314.   {0.0, 0.0, 0.0, 0.0};
  1315.   static float bevel_mat_diffuse[] =
  1316.   {1.0, 0.0, 0.0, 0.0};
  1317.  
  1318.   glEnable(GL_CULL_FACE);
  1319.   glCullFace(GL_BACK);
  1320.   glEnable(GL_DEPTH_TEST);
  1321.   glClearDepth(1.0);
  1322.  
  1323.   glClearColor(0.5, 0.5, 0.5, 0.0);
  1324.   glLightfv(GL_LIGHT0, GL_AMBIENT, light0_ambient);
  1325.   glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_diffuse);
  1326.   glLightfv(GL_LIGHT0, GL_SPECULAR, light0_specular);
  1327.   glLightfv(GL_LIGHT0, GL_POSITION, light0_position);
  1328.   glEnable(GL_LIGHT0);
  1329.  
  1330.   glLightModelfv(GL_LIGHT_MODEL_LOCAL_VIEWER, lmodel_local);
  1331.   glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, lmodel_twoside);
  1332.   glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
  1333.   glEnable(GL_LIGHTING);
  1334.  
  1335.   glMaterialfv(GL_FRONT, GL_AMBIENT, bevel_mat_ambient);
  1336.   glMaterialfv(GL_FRONT, GL_SHININESS, bevel_mat_shininess);
  1337.   glMaterialfv(GL_FRONT, GL_SPECULAR, bevel_mat_specular);
  1338.   glMaterialfv(GL_FRONT, GL_DIFFUSE, bevel_mat_diffuse);
  1339.  
  1340.   glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
  1341.   glEnable(GL_COLOR_MATERIAL);
  1342.   glShadeModel(GL_FLAT);
  1343.  
  1344.   trackball(curquat, 0.0, 0.0, 0.0, 0.0);
  1345.   srandom(time(NULL));
  1346. }
  1347.  
  1348. static void
  1349. Usage(void)
  1350. {
  1351.   printf("Usage: puzzle [-s]\n");
  1352.   printf("   -s:  Run in single buffered mode\n");
  1353.   exit(-1);
  1354. }
  1355.  
  1356. void
  1357. visibility(int v)
  1358. {
  1359.   if (v == GLUT_VISIBLE) {
  1360.     visible = 1;
  1361.   } else {
  1362.     visible = 0;
  1363.   }
  1364.   changeState();
  1365. }
  1366.  
  1367. void
  1368. menu(int choice)
  1369. {
  1370.    switch(choice) {
  1371.    case 1:
  1372.       toggleSolve();
  1373.       break;
  1374.    case 2:
  1375.       reset();
  1376.       break;
  1377.    case 3:
  1378.       exit(0);
  1379.       break;
  1380.    }
  1381. }
  1382.  
  1383. int
  1384. main(int argc, char **argv)
  1385. {
  1386.   long i;
  1387.  
  1388.   glutInit(&argc, argv);
  1389.   for (i = 1; i < argc; i++) {
  1390.     if (argv[i][0] == '-') {
  1391.       switch (argv[i][1]) {
  1392.       case 's':
  1393.         doubleBuffer = 0;
  1394.         break;
  1395.       default:
  1396.         Usage();
  1397.       }
  1398.     } else {
  1399.       Usage();
  1400.     }
  1401.   }
  1402.  
  1403.   glutInitWindowSize(W, H);
  1404.   if (doubleBuffer) {
  1405.     glutInitDisplayMode(GLUT_DEPTH | GLUT_RGB | GLUT_DOUBLE | GLUT_MULTISAMPLE);
  1406.   } else {
  1407.     glutInitDisplayMode(GLUT_DEPTH | GLUT_RGB | GLUT_SINGLE | GLUT_MULTISAMPLE);
  1408.   }
  1409.  
  1410.   glutCreateWindow("glpuzzle");
  1411.  
  1412.   init();
  1413.  
  1414.   glGetIntegerv(GL_VIEWPORT, viewport);
  1415.  
  1416.   printf("\n");
  1417.   printf("r   Reset puzzle\n");
  1418.   printf("s   Solve puzzle (may take a few seconds to compute)\n");
  1419.   printf("d   Destroy a piece - makes the puzzle easier\n");
  1420.   printf("b   Toggles the depth buffer on and off\n");
  1421.   printf("\n");
  1422.   printf("Left mouse moves pieces\n");
  1423.   printf("Middle mouse spins the puzzle\n");
  1424.   printf("Right mouse has menu\n");
  1425.  
  1426.   glutReshapeFunc(Reshape);
  1427.   glutDisplayFunc(redraw);
  1428.   glutKeyboardFunc(keyboard);
  1429.   glutMotionFunc(motion);
  1430.   glutMouseFunc(mouse);
  1431.   glutVisibilityFunc(visibility);
  1432.   glutCreateMenu(menu);
  1433.   glutAddMenuEntry("Solve", 1);
  1434.   glutAddMenuEntry("Reset", 2);
  1435.   glutAddMenuEntry("Quit", 3);
  1436.   glutAttachMenu(GLUT_RIGHT_BUTTON);
  1437.   glutMainLoop();
  1438.   return 0;             /* ANSI C requires main to return int. */
  1439. }
  1440.